/**
 * @author Tobias Boehm
 *
 * 29.03.2011
 */
package org.anddev.andengine.extension.tbsengine.match.gamestate;

import java.util.HashMap;
import java.util.Random;

import org.anddev.andengine.extension.tbsengine.faction.AbsBaseFaction;
import org.anddev.andengine.extension.tbsengine.gameobject.Unit;
import org.anddev.andengine.extension.tbsengine.match.AbsMatch;
import org.anddev.andengine.extension.tbsengine.match.Round;
import org.anddev.andengine.extension.tbsengine.match.Turn;
import org.anddev.andengine.extension.tbsengine.player.BasePlayer;
import org.anddev.andengine.extension.tbsengine.region.RegionController;
import org.anddev.andengine.extension.tbsengine.resource.AbsBaseResourceType;
import org.anddev.andengine.extension.tbsengine.resource.ResourceAccount;
import org.anddev.andengine.extension.tbsengine.team.Team;

/**
 * This class represents an abstract player game state. The
 * {@link AbsPlayerGameState} contains only information which
 * is noted by a player which again is only a part of the whole
 * game state information handled by {@link AbsGlobalGameState}.
 * <p>
 * Notice:<br>
 * Instances of this class are {@link Comparable}. An {@link AbsGlobalGameState}
 * is equal to another if their {@link #mGameStateID} are equal.
 *   
 * @author Tobias Boehm
 *
 * @param <FactionClass> - Your implementation of {@link AbsBaseFaction}
 */
public abstract class AbsPlayerGameState<FactionClass extends AbsBaseFaction> implements Comparable<AbsPlayerGameState>{

	/**
	 * The RegionController of this player game state
	 * which handles all region related information.
	 */
	private RegionController mRegionController;
	
	/**
	 * A map of {@link AbsBaseResourceType}s -> {@link ResourceAccount}s which are related
	 * to this player game state.
	 */
	private final HashMap<AbsBaseResourceType, ResourceAccount> mResourceTypeAccountsMap = new HashMap<AbsBaseResourceType, ResourceAccount>();
	
	/**
	 * A map of all unitIds -> units owned by this player
	 * game state.
	 */
	private final HashMap<String,Unit> mUnitIDsUnitsMap = new HashMap<String, Unit>();
	
	/**
	 * The faction of this player game state.
	 */
	private final FactionClass mFaction;
	
	/**
	 * The current team of this player game state.
	 */
	private Team mTeam;
	
	/**
	 * The current player of this player game state
	 */
	private final BasePlayer mPlayer;
	
	/**
	 * The random generator of this player game state which is important for all
	 * kinds of random results for events or fights.
	 * 
	 * @see #mRandomSeed
	 */
	private final Random mRandomGenerator;
	
	/**
	 * The seed (announced by the game server) which will
	 * be used to initialize the {@link #mRandomGenerator}.
	 * 
	 * @see #mRandomGenerator
	 */
	private final long mRandomSeed;
	
	/**
	 * The game state id of this game state
	 * which is unique inside the same {@link AbsMatch}.
	 */
	private final int mGameStateID;
	
	/**
	 * A flag which indicates that this game state is defeated and
	 * can be ignored in further {@link Turn}s and {@link Round}s.
	 * 
	 * @see {@link Round#Round(int, AbsGlobalGameState)}
	 * @see {@link Round#startNextTurn()}
	 */
	private boolean mDefeated;
	
		
	/**
	 * With this constructor you can create and initialize a
	 * player game state. 
	 * 
	 * @param pGameStateID - The player game state ID which has to be unique inside the same {@link AbsMatch}
	 * @param pPlayer - The current player which uses this game state.
	 * @param pFaction - The faction of this game state.
	 * @param pTeam - The current team of this game state.
	 * @param pRandomSeed - The random seed provided by the game server - see {@link #mRandomGenerator}
	 * @param pIsDefeated - The state of this game state - see {@link #mDefeated}
	 */
	public AbsPlayerGameState(final int pGameStateID, final BasePlayer pPlayer, final FactionClass pFaction, final Team pTeam, final long pRandomSeed, final boolean pIsDefeated){
		
		this.mDefeated = pIsDefeated;
		
		this.mPlayer = pPlayer;
		this.mFaction = pFaction;
		this.mTeam = pTeam;
		this.mGameStateID = pGameStateID;
		
		this.mRandomSeed = pRandomSeed;
		this.mRandomGenerator = new Random(pRandomSeed);
	}

	/**
	 * @return the mTeam
	 */
	public Team getTeam() {
		return mTeam;
	}

	/**
	 * @param mTeam the mTeam to set
	 */
	public void setTeam(Team mTeam) {
		this.mTeam = mTeam;
	}

	/**
	 * @return the mFaction
	 */
	public FactionClass getFaction() {
		return mFaction;
	}

	/**
	 * @return the mPlayer
	 */
	public BasePlayer getPlayer() {
		return mPlayer;
	}

	/**
	 * @return the mRandomGenerator
	 */
	public Random getRandomGenerator() {
		return mRandomGenerator;
	}

	/**
	 * @return the mRandomSeed
	 */
	public long getRandomSeed() {
		return mRandomSeed;
	}

	/**
	 * @return the mGameStateID
	 */
	public int getGameStateID() {
		return mGameStateID;
	}
	
	
	/**
	 * Player game states get compared by their {@link #mGameStateID}.
	 */
	@Override
	public int compareTo(AbsPlayerGameState another) {
		
		if(this.mGameStateID < another.getGameStateID()){
		
			return -1;
			
		}else if(this.mGameStateID > another.getGameStateID()){
			
			return 1;
			
		}else{
			
			return 0;
		}
	}

	/**
	 * @return the mDefeated
	 */
	public boolean isDefeated() {
		return mDefeated;
	}

	/**
	 * @param mDefeated the mDefeated to set
	 */
	public void setDefeated(boolean mDefeated) {
		this.mDefeated = mDefeated;
	}
}
